import os
import math
import json
import tkinter
from datetime import datetime
from tkinter import colorchooser


class MainWindow():
    """
    主窗口
    """

    def __init__(self, window_name):
        # 创建一个窗口
        self.window = tkinter.Tk()
        self.window.title(window_name)
        # 设置基础参数
        self.window.iconbitmap("./src/favsion.ico")
        self.window.geometry("800x600")
        self.window.resizable(False, False)

        # 分为左右容器并填充到主窗口
        self.leftFrame = tkinter.Frame(self.window)
        self.rightFrame = tkinter.Frame(self.window)

        # 位置配置
        self.leftFrame.config(width=self.window.winfo_width() * 0.3, height=self.window.winfo_height(), bg="#242424")
        self.leftFrame.pack(side="left", fill="both", expand=False)

        self.rightFrame.config(bg="#ffffff")
        self.rightFrame.pack(side="right", fill="both", expand=True)

        self.clock_module = None
        self.config_module = None
        self.colors = {}

    def set_clients(self, clock_module, config_module):
        self.clock_module = clock_module
        self.config_module = config_module

    def get_win_window(self):
        if self.window:
            return self.window
        return False

    def get_win_rframe(self):
        if self.rightFrame:
            return self.rightFrame
        return False

    def get_win_lframe(self):
        if self.leftFrame:
            return self.leftFrame
        return False

    def change_clock_color(self, tag, color_str):
        self.clock_module.change_color(tag, color_str)

    def set_colors(self, colors):
        self.colors = colors

    def get_colors(self):
        return self.colors["clock_color"]

    def run_window(self):
        """
        启动
        @return:
        """
        self.window.mainloop()


# 时钟
class MyClock():
    def __init__(self, window_module):
        self.window_module = window_module
        self.window = window_module.get_win_window()
        # 创建颜色配置对象
        # 创建画板，时钟就画在上面
        self.Canvas = tkinter.Canvas(self.window_module.get_win_rframe())
        self.Canvas.config(bg="white")
        self.Canvas.pack(anchor="center", expand=True, fill="both")
        # 时钟圆心像素
        self.O_x = self.window.winfo_width() * 0.4
        self.O_y = self.window.winfo_height() * 0.5
        # 时钟半径
        self.radius = 250
        # 时间变量
        self.second = datetime.now().second
        self.minute = datetime.now().minute
        self.hour = datetime.now().hour

        # 装饰颜色
        # {"sec": "#ffffff", "hour": "#ffffff", "min": "#ffffff", "bg": "#242424", "num": "#ffffff"}
        self.clock_colors = self.window_module.get_colors()

        # 图标
        self.sun = tkinter.PhotoImage(file="./src/sun.png", width=60, height=60),  # 对应 "XII"
        self.cat = tkinter.PhotoImage(file="./src/cat.png", width=60, height=60),  # 对应 "III"
        self.cock = tkinter.PhotoImage(file="./src/cock.png", width=60, height=60),  # 对应 "VI"
        self.dog = tkinter.PhotoImage(file="./src/dog.png", width=60, height=60)  # 对应 "IX"
        # 创建时钟：实例化对象时创建
        self.create_clock()
        self.run_clock()

    def run_clock(self):
        """
        运行时钟，不断更新重绘指针位置
        @return:
        """
        print(f"当前时钟时间：{self.hour:02d} : {self.minute:02d} : {self.second:02d}")
        self.update_time()

    def draw_hand(self, value, length, color, width, tail_length):
        """
        绘制指针
        @param value: 时间值 0-59
        @param length: 长度
        @param color: 颜色
        @param width: 指针宽度
        @return:
        """
        # 使用极坐标计算直线终点
        angle = math.radians(value * 6 - 90)
        x = self.O_x + length * math.cos(angle)
        y = self.O_y + length * math.sin(angle)
        self.Canvas.create_line(self.O_x, self.O_y, x, y, width=width, fill=color, tags="hand", arrow='last',
                                arrowshape=(20, 10, 2))
        # 计算方向向量
        dx = x - self.O_x
        dy = y - self.O_y
        # 计算反方向延长的新起点
        length = math.sqrt(dx ** 2 + dy ** 2)
        new_O_x = self.O_x - (dx / length) * tail_length
        new_O_y = self.O_y - (dy / length) * tail_length
        # 创建反方向延长的线段
        self.Canvas.create_line(new_O_x, new_O_y, x, y, width=width, fill=color, tags="hand")

    def change_color(self, tag, color_str):
        """
        改变颜色
        @return:
        """
        # 颜色配置更新
        # {"sec": "#ffffff", "hour": "#ffffff", "min": "#ffffff", "bg": "#242424", "num": "#ffffff"}
        self.clock_colors[tag] = color_str

        # 删除之前的时钟
        self.Canvas.delete("bg")
        self.Canvas.delete("num")
        self.Canvas.delete("icon")
        # 重新绘制时钟
        self.create_clock()

    def update_time(self):
        """
        每秒更新时钟状态
        @return:
        """
        # 更新指针位置
        self.Canvas.delete("hand")
        self.Canvas.delete("tips")
        self.draw_hand(self.second, 220, self.clock_colors["sec"], 1, 50)
        self.draw_hand(self.minute, 120, self.clock_colors["hour"], 2, 30)
        self.draw_hand(self.hour * 5 + self.minute / 12, 60, self.clock_colors["min"], 3, 20)

        # 更新时间变量
        self.second += 1
        if self.second == 60:
            self.second = 0
            self.minute = (self.minute + 1) % 60
            if self.minute == 0:
                self.hour = (self.hour + 1) % 12
        # 映射时间和对应的文本内容
        time_text_map = {
            # (小时，分钟)："提示信息"
            (12, 1): "The sun shines in the sky",
            (3, 1): "猫猫在捣蛋",
            (6, 1): "公鸡在尖叫",
            (9, 1): "添狗喊你起床啦",
            (0, 1): "Good night !!!",
            (15, 1): "开始复习啦",
            (18, 1): "干饭呢",
            (21, 1): "晚安，玛卡巴卡",
        }

        # 获取当前时间对应的文本内容，默认 Cherish every second
        text_content = time_text_map.get((datetime.now().hour, datetime.now().minute), "Cherish every second")

        # 提示文本加入画布
        self.Canvas.create_text(self.O_x, self.O_y + 100, text=text_content, fill=self.clock_colors["num"],
                                font=("Times New Roman", 12 if text_content != "Cherish every second" else 18),
                                tags="tips")
        # 启动定时器，每1000毫秒执行一次更新
        self.window.after(1000, self.update_time)

    def create_clock(self):
        """
        绘制圆盘，数字，图标
        @return:
        """
        # 绘制时钟圆盘
        self.Canvas.create_oval(
            self.O_x - self.radius, self.O_y - self.radius,
            self.O_x + self.radius, self.O_y + self.radius,
            fill=self.clock_colors["bg"],
            width=0,
            tags="bg"
        )
        # 添加四个角的罗马数字
        font_size = 18  # 字体大小
        # 罗马数字和它们的相对位置
        roman_numerals = [
            ("XII", (self.O_x, self.O_y - self.radius + 20)),
            ("III", (self.O_x + self.radius - 20, self.O_y)),
            ("VI", (self.O_x, self.O_y + self.radius - 20)),
            ("IX", (self.O_x - self.radius + 20, self.O_y))
        ]
        # 循环遍历绘制时钟上的数字
        for numeral, pos in roman_numerals:
            self.Canvas.create_text(pos, text=numeral, fill=self.clock_colors["num"],
                                    font=("Times New Roman", font_size), tags="num")

            # 将图片添加到靠近罗马数字的位置
            icon_distance = 80
            icons = [
                # 时钟图标
                self.sun,  # 对应 "XII"
                self.cat,  # 对应 "III"
                self.cock,  # 对应 "VI"
                self.dog  # 对应 "IX"
            ]
            # 循环遍历将图片绘制到画板上
            for i, (numeral, pos) in enumerate(roman_numerals):
                # 极坐标法计算位置
                angle_rad = math.atan2(pos[1] - self.O_y, pos[0] - self.O_x)
                icon_x = self.O_x + (self.radius - icon_distance) * math.cos(angle_rad)
                icon_y = self.O_y + (self.radius - icon_distance) * math.sin(angle_rad)
                self.Canvas.create_image(icon_x, icon_y, image=icons[i], anchor="center", tags="icon")
class MyConfig:
    """
    参数配置保存到文件
    """

    def __init__(self, window_module):
        self.window_module = window_module
        self.leftFrame = window_module.get_win_lframe()
        # 默认配置
        self.config_colors = {
            "clock_color": {"sec": "#ffffff", "hour": "#ffffff", "min": "#ffffff", "bg": "#242424", "num": "#ffffff"}}
        self.config_path = "config.json"
        self.load_config()

        # 创建标签里的容器，并填充到左边容器
        self.leftSecFrame = tkinter.Frame(self.leftFrame, bg="#242424")
        self.leftMinFrame = tkinter.Frame(self.leftFrame, bg="#242424")
        self.leftHourFrame = tkinter.Frame(self.leftFrame, bg="#242424")
        self.leftNumFrame = tkinter.Frame(self.leftFrame, bg="#242424")
        self.leftIconFrame = tkinter.Frame(self.leftFrame, bg="#242424")
        self.leftBgFrame = tkinter.Frame(self.leftFrame, bg="#242424")

        # 创建文本标签
        self.color_lab = tkinter.Label(self.leftFrame, text="颜色配置", font=("微软雅黑", 12), fg="white", bg="#242424")
        self.copyright_lab = tkinter.Label(self.leftFrame, text="PASSLINK", font=("微软雅黑", 12), fg="white",
                                           bg="#242424")
        self.sec_lab = tkinter.Label(self.leftSecFrame, text="秒针", font=("微软雅黑", 12), fg="white", bg="#242424")
        self.min_lab = tkinter.Label(self.leftMinFrame, text="分针", font=("微软雅黑", 12), fg="white", bg="#242424")
        self.hour_lab = tkinter.Label(self.leftHourFrame, text="时针", font=("微软雅黑", 12), fg="white", bg="#242424")
        self.num_lab = tkinter.Label(self.leftNumFrame, text="数字", font=("微软雅黑", 12), fg="white", bg="#242424")
        self.bg_lab = tkinter.Label(self.leftBgFrame, text="背景", font=("微软雅黑", 12), fg="white", bg="#242424")

        # 创建按钮
        self.sec_button = tkinter.Button(self.leftSecFrame, width=10, text=self.config_colors["clock_color"]["hour"],
                                         bg=self.config_colors["clock_color"]["hour"],
                                         command=lambda: self.color_chooser("sec"))
        self.min_button = tkinter.Button(self.leftMinFrame, width=10, text=self.config_colors["clock_color"]["min"],
                                         bg=self.config_colors["clock_color"]["min"],
                                         command=lambda: self.color_chooser("min"))
        self.hour_button = tkinter.Button(self.leftHourFrame, width=10, text=self.config_colors["clock_color"]["hour"],
                                          bg=self.config_colors["clock_color"]["hour"],
                                          command=lambda: self.color_chooser("hour"))
        self.num_button = tkinter.Button(self.leftNumFrame, width=10, text=self.config_colors["clock_color"]["num"],
                                         bg=self.config_colors["clock_color"]["num"],
                                         command=lambda: self.color_chooser("num"))
        self.bg_button = tkinter.Button(self.leftBgFrame, width=10, text=self.config_colors["clock_color"]["bg"],
                                        bg=self.config_colors["clock_color"]["bg"],
                                        command=lambda: self.color_chooser("bg"))
        # 左侧控件位置
        self.color_lab.pack(side="top", fill="x", anchor="n", pady=10)
        self.leftSecFrame.pack(anchor="center", pady=10, padx=10, fill="x")
        self.leftMinFrame.pack(anchor="center", pady=10, padx=10, fill="x")
        self.leftHourFrame.pack(anchor="center", pady=10, padx=10, fill="x")
        self.leftNumFrame.pack(anchor="center", pady=10, padx=10, fill="x")
        self.leftIconFrame.pack(anchor="center", pady=10, padx=10, fill="x")
        self.leftBgFrame.pack(anchor="center", pady=10, padx=10, fill="x")

        # 标签与选色按钮
        self.sec_lab.pack(side="left", expand=True, fill="x")
        self.sec_button.pack(side="right", expand=True, fill="x")
        self.min_lab.pack(side="left", expand=True, fill="x")
        self.min_button.pack(side="left", expand=True, fill="x")
        self.hour_lab.pack(side="left", expand=True, fill="x")
        self.hour_button.pack(side="left", expand=True, fill="x")
        self.num_lab.pack(side="left", expand=True, fill="x")
        self.num_button.pack(side="left", expand=True, fill="x")
        self.bg_lab.pack(side="left", expand=True, fill="x")
        self.bg_button.pack(side="left", expand=True, fill="x")
        self.copyright_lab.pack(side="bottom", fill="x", anchor="s", pady=20)

    def color_chooser(self, tag):
        """
        打开选色器，并更改颜色参数
        @param tag: 修改目标
        @return:
        """
        # 使用Tk自带的选色器colorchooser，运行选色器
        color_code = colorchooser.askcolor()
        # print(color_code)
        # ((255, 0, 0), '#ff0000') Tk只支持其中的'#ff0000'，所以选择第二个
        color_str = str(color_code[1])
        # print(color_str)
        if color_str == "None":  # 如果用户没有选择颜色
            print("用户没有确认选择颜色")
            return
        # 根据选择的按钮更新颜色
        if tag == "num":
            self.num_button.config(bg=color_str, text=color_str)
        elif tag == "bg":
            self.bg_button.config(bg=color_str, text=color_str)
        elif tag == "min":
            self.min_button.config(bg=color_str, text=color_str)
        elif tag == "hour":
            self.hour_button.config(bg=color_str, text=color_str)
        elif tag == "sec":
            self.sec_button.config(bg=color_str, text=color_str)
        # 修改配置文件，重绘时钟
        self.edit_config(tag, color_str)
        # 通知时钟改变颜色
        self.window_module.change_clock_color(tag, color_str)

    def load_config(self):
        """
        重新加载配置文件并更新参数
        @return:
        """
        try:
            # 检查配置文件是否存在
            if not os.path.exists(self.config_path):
                with open(self.config_path, 'w') as file:
                    json.dump(self.config_colors, file, indent=4)
            # 打开文件读取配置
            with open(self.config_path, 'r') as file:
                self.config_colors = json.load(file)
        except Exception as e:
            print(f"配置文件读取失败: {e}")
            print(self.config_colors)
        finally:
            # 将读取的配置发送给通信员
            self.window_module.set_colors(self.config_colors)

    def edit_config(self, tag, value):
        """
        修改参数并保存
        @param tag: 修改参数目标
        @param value: 修改值
        @return:
        """
        try:
            self.config_colors["clock_color"][tag] = str(value)
            with open(self.config_path, 'w') as file:
                json.dump(self.config_colors, file, indent=4)
        except Exception as e:
            print(f"配置文件写入失败: {e}")

if __name__ == "__main__":

    # 创建主窗口
    main_window = MainWindow("时钟")
    # 创建配置模块
    config_module = MyConfig(main_window)
    clock_module = MyClock(main_window)
    main_window.set_clients(clock_module, config_module)
    main_window.run_window()
